package org.cloud.scheduler.config;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;

import javax.annotation.Resource;
import javax.sql.DataSource;

import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
import org.springframework.transaction.interceptor.TransactionInterceptor;

import lombok.Setter;

/**
 * 应用级别事务管理器配置
 * 
 * @author wangyuan
 * @since 2018年7月20日
 */
@Configuration
@EnableTransactionManagement
@ConfigurationProperties("sloth.transaction")
public class TransactionConfig implements TransactionManagementConfigurer {
    
    @Setter
    private String execution;
    
    private Map<String, String> attributes = new LinkedHashMap<>();
    
    {
        //可修改
        attributes.put("save*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-Exception");
        attributes.put("insert*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-Exception");
        
        attributes.put("remove*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-Exception");
        attributes.put("delete*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-Exception");
        
        attributes.put("update*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-Exception");
        
        attributes.put("do*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-Exception");
        attributes.put("deal*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-Exception");
        
        //只读
        attributes.put("select*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly,-Exception");//分页查询的方法开头
        attributes.put("get*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly,-Exception");//返回单个值的方法开头
        attributes.put("list*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly,-Exception");//返回多个值的方法开头
        attributes.put("count*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly,-Exception");//统计方法开头
        attributes.put("*", "PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly,-Exception");
    }
    
    @Resource(name = "transactionManager")
    private PlatformTransactionManager transactionManager;

    @Bean("transactionManager")
    public PlatformTransactionManager transactionManager(DataSource dataSource){
        return new DataSourceTransactionManager(dataSource);
    }
    
    public PlatformTransactionManager returnTransactionManager(@Qualifier("transactionManager") PlatformTransactionManager transactionManager) {
        return transactionManager;
    }
    
    @Bean("transactionInterceptor")
    @Qualifier("transactionManager")
    public TransactionInterceptor TransactionInterceptor(PlatformTransactionManager primaryTransactionManager){
        TransactionInterceptor interceptor = new TransactionInterceptor();
        interceptor.setTransactionManager(primaryTransactionManager);
        
        Properties transactionAttributes = new Properties();
        
        for(Entry<String, String> item : attributes.entrySet()){
            transactionAttributes.put(item.getKey(), item.getValue());
        }
        
        interceptor.setTransactionAttributes(transactionAttributes);
        
        return interceptor;
    }
    
    @Bean("transactionPointcut")
    public AspectJExpressionPointcut aspectJExpressionPointcut(){
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(execution);
        return pointcut;
    }
 
    @Bean("transactionPointcutAdvisor")
    public DefaultPointcutAdvisor defaultPointcutAdvisor(@Qualifier("transactionPointcut") AspectJExpressionPointcut pointcut, 
            @Qualifier("transactionInterceptor") TransactionInterceptor advice){
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        advisor.setPointcut(pointcut);
        advisor.setAdvice(advice);
        advisor.setOrder(0);
        return advisor;
    }
    
    @Override
    public PlatformTransactionManager annotationDrivenTransactionManager() {
        return transactionManager;
    }
}
